<?php
namespace wogu2\mvc;

use ArrayObject;
use InvalidArgumentException;
use wogu2\stdlib\RequestInterface;
use wogu2\stdlib\ResponseInterface;
use wogu2\mvc\action\ActionInterface;

class Dispatcher implements DispatcherInterface
{
    private $_config = null;
    private $_runtime = null;
    private $_request = null;
    
    private $_action = null;
    private $_dispatched = false;
    private $_runSystemInterceptors = true;
    private $_systemInterceptors = array();
    
    public function setConfig($config) {
        $this->_config = $config;
        foreach($config['interceptors'] as $interceptorName) {
            $this->_systemInterceptors[] = new $interceptorName;
        }
    }
    
    public function setRequest(RequestInterface $request) {
        $this->_request = $request;
    }
    
    public function getRequest() {
        return $this->_request;
    }
    
    public function setRuntime(ArrayObject $runtime) {
        $this->_runtime = $runtime;
    }
    
    public function getRuntime() {
        return $this->_runtime;
    }
    
    public function setDispatched($dispatched) {
        $this->_dispatched = $dispatched;
    }
    
    public function dispatch() {
        $this->_dispatched = false;
        $actionConfig = $this->_runtime->actionConfig;

        if(!isset($actionConfig['resultConfig'])) {
            include $actionConfig['path'];
            $this->_action = new $actionConfig['class'];

            $interceptors = $this->_runSystemInterceptors ? $this->_systemInterceptors : array();
            if(isset($actionConfig['interceptors'])) {
                foreach($actionConfig['interceptors'] as $interceptorName) {
                    $interceptors[] = new $interceptorName;
                }
            }
            
            foreach($interceptors as $interceptor) {
                $interceptor->init($this);
                $resultCode = $interceptor->intercept();
                if($resultCode !== null) break;
            }
    
            if(!$this->_dispatched) {
                $resultCode = $this->executeAction();
            }
            
            if($resultCode === null)
                $resultCode = ActionInterface::SUCCESS;
            
            if(!isset($actionConfig['results'][$resultCode])) {
                throw new InvalidArgumentException('no result for result code \'' . $resultCode . '\' in action config');
            }
            
            $resultConfig = $actionConfig['results'][$resultCode];
        } else {
            $resultConfig = $actionConfig['result-config'];
        }
        
        $this->_runSystemInterceptors = false;
        $result = new $resultConfig['class'];
        $result->init($this);
        $result->execute($resultConfig);
    }
    
    public function executeAction() {
        $this->_action->setRuntime($this->_runtime);
        $resultCode = $this->_action->execute();
        $this->_dispatched = true;
        return $resultCode;
    }
}